# -*- coding: utf-8 -*-

# $Id: python_package.py 7 2012-09-01 17:32:56Z alexis.roda.villalonga@gmail.com $

"""This modules provides some convenience classes to ease the
management of python packages.

In that context a *package* is a directory with and `__init__.py`
while a *module* is any `file.py`.
"""

import inspect
import os.path

from dja_skel.lib.files import TextFile


def _ispackage(pkg):
    return inspect.ismodule(pkg) and hasattr(pkg, "__path__")


class PythonPackage(object):
    """Python package.
    """

    def __init__(self, path=None, pkg=None):
        """Constructor.

        :param path:
        :param pkg:
        """
        if not ((path is None) ^ (pkg is None)):
            raise ValueError(
                "Must specify either 'path' or 'pkg' but not both."
                )
        if path is not None:
            self._root = path
        else:
            if not _ispackage(pkg):
                raise ValueError("'%r' is not a package")
            # under wich circumstances len(pkg.__path__) > 1 ?
            self._root = pkg.__path__[0]

    @property
    def root(self):
        return self._root

    def is_file(self, rel_path):
        """Checks if `rel_path` points to a file.

        :param rel_path:

        :raises:
        :returns: True if `rel_path` is a file, False otherwise.
        :rtype: bool
        """
        return os.path.isfile(os.path.join(self._root, rel_path))

    def is_dir(self, rel_path):
        """Cheks if `rel_path` points to a directory.

        :param rel_path:

        :raises:
        :returns: True if `rel_path` is a directory, False otherwise.
        :rtype: bool
        """
        return os.path.isdir(os.path.join(self._root, rel_path))

    def is_module(self, dot_path):
        """Checks if `dot_path` points to a module.

        :param dot_path:

        :raises:
        :returns: True if `dot_path` is a module, False otherwise
        :rtype: bool
        """
        rel_path = os.path.join(*(dot_path.split("."))) + ".py"
        return self.is_file(rel_path)

    def is_package(self, dot_path):
        """Checks if `dot_path` points to a package.

        :param dot_path:

        :raises:
        :returns: True if `dot_path` is a package, False otherwise.
        :rtype: bool
        """
        rel_path = os.path.join(*(dot_path.split(".")))
        init_path = os.path.join(rel_path, "__init__.py")
        return self.is_dir(rel_path) and self.is_file(init_path)

    def get_file(self, rel_path, encoding="utf-8"):
        """
        """
        abs_path = os.path.join(self._root, rel_path)
        return TextFile(abs_path, encoding)


class DjangoApp(PythonPackage):
    """Django app
    """

    def __init__(self, appname):
        """Constructor.

        :param appname:
        """
        from django.db.models.loading import cache

        self._appname = appname
        app = cache.get_app(appname, emptyOK=True)
        if app is None:
            raise ValueError(appname)
        root = os.path.dirname(app.__file__)
        if root.endswith("models"):
            root = os.path.dirname(root)
        super(DjangoApp, self).__init__(path=root)
        self.models = app


class DjangoProject(PythonPackage):
    """Django project
    """

    def __init__(self):
        """Constructor.
        """
        settings = os.environ["DJANGO_SETTINGS_MODULE"]
        module = __import__(settings)
        super(DjangoProject, self).__init__(
            path=os.path.dirname(module.__file__)
            )

